/* 
 * File:   FreeList.h
 * Author: chris
 *
 * Created on January 25, 2009, 8:39 PM
 */

#ifndef _FREELIST_H
#define	_FREELIST_H

#include "BlockLinkedList.h"
#include "BlockGroup.h"
#include "Disk.h"

/**
 * This class represents a special BlockLinkedList -- the Free List. The Free List keeps track of
 * unused blocks on the Disk device. The Free List can be used
 * to spawn (create) other BlockLinkedList's, assuming there are still free blocks in the Free List.
 * Uses block 0 on the disk as the master block to contain information about the location
 * of the Free List.
 *
 * @author Christopher G. Prince
 */
class FreeList : public BlockLinkedList {
public:
    /** The default number of blocks for a Disk to be used with this class.
     */
    /* Use this only for simulated disks. */
    const static int DEFAULT_NUMBER_OF_BLOCKS = 100;
	
   /** This constructor generates a RAM object representing the free list
     * for the Disk.
     *
     * @param disk is the Disk object where the FreeList is located or where it is to be created.
     *
     * @param createFreeList should be true if a free list has not yet been created for this Disk.
     * This will initialize the free list for this BlockGroup (it will then contain all blocks
     * on the disk aside from the master block). Otherwise,
     * reads the starting and ending block numbers for the free list from block 0. That is,
     * set this parameter to true to initialize the free list and loose all existing data, and to
     * false to use the existing free list.
     *
     * @throws BlockGroupException if there was a problem opening or intializing the free list.
     */
    FreeList(Disk *disk, bool createFreeList);
    
    /** Writes out the current start block
     * of the free list to block 0.
     *
     * @return true iff the Free List could be closed.
     */
	
    bool Close(); 
	
    /** Returns all blocks of the BlockLinkedList to the Free List.
     *
     * @param bll after this call, this BlockLinkedList has been deallocated.
     *
     */
    void Return(BlockLinkedList *bll);
	
    /** Spawn a new BlockGroup from the Free List.
     *
     * The new BlockGroup has one block to start. This block is updated on disk by this call.
     *
     * @returns A new BlockGroup, or NULL if one could not be created.
     */
    BlockGroup *CreateNew();
    
    static void Test(bool menu=true, const char *filename=NULL, int StartBlockNumber[]=NULL);

private:
	/** Do some basic debugging. Prints out the start, end, and number of blocks in the free list.
	 Prints out the blocks in the free list. 
	 The StartBlockNumber[i] is taken to be the starting block number of a BlockGroup. 
	 Iterates through
	 the blocks in that BlockGroup until its end is reached, printing out the block numbers.
	 */
	static void DebugDisk(const char *filename, int StartBlockNumbers[]);

public:

    /**	Iterate over the blocks of a block group, from a StartBlockNumber
	 *	to the end of the BlockGroup, printing out the block numbers, and doing
     *  sanity checks on the block numbers. Returns the last block number in the
     *  block group.
     */
    static int TestBlockGroup(int startBlockNumber, FreeList *mother);

    /* For testing. Performs an array of integrity tests on the free list.
     */
    static void Check(FreeList *mother);

private:
    // The only issue with this variable is that super-class methods can still be called...
    bool m_closed; // has the FreeList been Closed?

    /** This method is used to reformat a disk. Reformat means linking
     * together all of the disk blocks (except for the master block) into
     * a single BlockLinkedList. Writes pointers to every disk block > 0 in order to accomplish this.
     *
     * If you use this call and you had
     * previously created other BlockLinkedList's from that free list, those lists should
     * no longer be used.
     *
     * @throws BlockGroupException
     * @throws BlockException when a Disk write fails.
     *
     */
    bool Reformat();
};

#endif	/* _FREELIST_H */

